package com.zysd.collection.scheduler.service.operate.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.lensyn.collect.common.utils.CheckSum;
import com.lensyn.collect.common.utils.JsonUtils;
import com.lensyn.collect.meters.codec.DataPackets;
import com.lensyn.collect.meters.codec.Head;
import com.lensyn.collect.meters.codec.Tail;
import com.lensyn.collect.meters.codec.linklayer.UserDataDomain;
import com.lensyn.collect.meters.netty.MessageHelper;
import com.lensyn.collect.meters.store.Message;
import com.lensyn.collect.meters.store.MetersMessage;
import com.zysd.collection.scheduler.entity.Operate;
import com.zysd.collection.scheduler.service.operate.OperateService;
import com.zysd.collection.scheduler.system.config.SysConfig;
import com.zysd.collection.scheduler.system.util.EncodeUtil;
import com.zysd.collection.scheduler.dao.OperateDao;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author ht
 * @date 2017/3/9
 */
@Service
public class OperateServiceImpl implements OperateService {

    private static final Logger LOGGER = LoggerFactory.getLogger(OperateServiceImpl.class);

    @Autowired
    private OperateDao operateDao;

    @Override
    public int updateById(Operate dto) {
        return operateDao.updateById(dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insert(Operate dto) {
        return operateDao.insert(dto);
    }

    @Override
    public Operate byId(Operate dto) {
        return operateDao.byId(dto);
    }

    @Override
    public Page<Operate> operateMsg(Integer region, Integer local, String startDate, Integer offset, Integer rows) {
        PageHelper.offsetPage(offset, rows);
        Page<Operate> page = (Page<Operate>) operateDao.operateMsg(region, local, startDate);
        return page;
    }

    @Override
    public Object operateById(Integer id) {
        Operate dto = new Operate();
        dto.setId(id);
        Operate operate = operateDao.byId(dto);
        String hex = getHex(operate.getReq());
        String json = getJson(operate.getReq());
        Map<String, Object> result = new HashMap<>(2);
        result.put("hex", hex);
        result.put("json", json);
        return result;
    }

    /**
     * 组装原始报文结构
     *
     * @param hex
     * @return
     */
    private String getHex(String hex) {
        byte[] asdu = EncodeUtil.hexStringToBytes(hex);
        ByteBuf buf = Unpooled.wrappedBuffer(asdu);
        DataPackets dpkg = new DataPackets(buf);
        dpkg.head.len.length = asdu.length;

        byte[] head = new byte[Head.Pipe.INSTANCE.bytes(dpkg.head)];
        Head.Pipe.INSTANCE.put(Unpooled.wrappedBuffer(head).resetWriterIndex(), dpkg.head);

        CheckSum cs = new CheckSum();
        cs.update(asdu);
        dpkg.tail.cs = cs.value();

        byte[] tail = new byte[Tail.Pipe.INSTANCE.bytes(dpkg.tail)];
        Tail.Pipe.INSTANCE.put(Unpooled.wrappedBuffer(tail).resetWriterIndex(), dpkg.tail);

        StringBuffer sb = new StringBuffer();
        format(sb, head);
        format(sb, asdu);
        format(sb, tail);
        return sb.toString();
    }

    /**
     * 获取解析结果类
     *
     * @param hex
     * @return
     */
    private String getJson(String hex) {
        try {
            byte[] asdu = EncodeUtil.hexStringToBytes(hex);
            ByteBuf buf = Unpooled.wrappedBuffer(asdu);
            UserDataDomain udata = new UserDataDomain();
            UserDataDomain.Pipe.INSTANCE.set(buf, udata);
            MetersMessage msgs = MessageHelper.unwrapDataPackets(SysConfig.convert(udata.address.region, udata.address.terminal), udata);
            StringWriter writer = new StringWriter();
            PrintWriter ps = new PrintWriter(writer);
            for (Message m : msgs.messages) {
                ps.format("FN:%d, PN:%d\n", m.di.fn, m.di.pn);
                JsonUtils.objectMapper.writeValue(ps, m.value);
                ps.println();
            }
            return writer.toString();
        } catch (Exception ex) {
            LOGGER.error("解码失败", ex.getMessage());
            return "解码失败。";
        }
    }

    private void format(StringBuffer sb, byte[] bytes) {
        for (int i = 0; i < bytes.length; ++i) {
            sb.append(String.format("%02x ", bytes[i] & 0xff));
        }
    }

}
